package timing.ukulele.project.provider;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import timing.ukulele.common.Constant;
import timing.ukulele.common.ResponseResult;
import timing.ukulele.common.ResultCode;
import timing.ukulele.common.flow.FlowData;
import timing.ukulele.common.form.FormTemplateData;
import timing.ukulele.common.item.ItemData;
import timing.ukulele.common.vo.ExecuteVO;
import timing.ukulele.common.vo.TaskVO;
import timing.ukulele.project.client.FlowClient;
import timing.ukulele.project.client.FormClient;
import timing.ukulele.project.client.ItemClient;
import timing.ukulele.project.persistent.Business;
import timing.ukulele.project.persistent.BusinessData;
import timing.ukulele.project.service.BusinessDataService;
import timing.ukulele.project.service.BusinessService;
import timing.ukulele.project.vo.BusinessDataVo;
import timing.ukulele.project.vo.BusinessItemVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

@RestController
@RequestMapping("/provider")
@Api("办理事项接口")
public class BusinessProviderController {

    private final BusinessService businessService;
    private final BusinessDataService businessDataService;
    @Resource
    private ItemClient itemClient;
    @Resource
    private FormClient formClient;
    @Resource
    private FlowClient flowClient;

    public BusinessProviderController(BusinessService businessService, BusinessDataService businessDataService) {
        this.businessService = businessService;
        this.businessDataService = businessDataService;
    }

    @GetMapping("/business/{businessCode}/{itemCode}/{action}")
    public ResponseResult<BusinessItemVo> item(
            @PathVariable(value = "businessCode") String businessCode,
            @PathVariable(value = "itemCode") String itemCode,
            @PathVariable(value = "action", required = false) String action,
            @RequestHeader(value = Constant.BUSINESS_USERNAME, required = false) String username) {
        if (action == null || "".equals(action)) {
            action = "create";
        }
        if (!(action.equalsIgnoreCase("create") || action.equalsIgnoreCase("modify")
                || action.equalsIgnoreCase("view") || action.equalsIgnoreCase("approval"))) {
            return ResponseResult.error("action参数错误，必须是create、modify、view、approval三个中的一个");
        }
        BusinessItemVo vo = new BusinessItemVo();
        final ResponseResult<ItemData> itemResult = itemClient.getByCode(itemCode);
        if (itemResult == null || itemResult.getCode() == ResultCode.RPC_ERROR.getCode())
            return ResponseResult.error("获取事项信息失败！");
        ItemData item = itemResult.getData();
        if (item == null)
            return ResponseResult.error("不存在该事项");
        vo.setItem(item);
        Business context = businessService.lambdaQuery().eq(Business::getBusinessCode, businessCode).one();
        if (context == null) {
            if (!action.equalsIgnoreCase("create")) {
                return ResponseResult.error("BusinessCode不存在");
            }
            Business businessContext = new Business();
            businessContext.setCreateBy(username);
            businessContext.setBusinessCode(businessCode);
            businessContext.setItemCode(itemCode);
            businessContext.setItemId(item.getId());
            businessContext.setItemName(item.getName());
            businessContext.setFlowId(item.getFlowId());
            businessContext.setFormId(item.getTemplateId());
            businessContext.setVersion(1);
            businessContext.setSystemId(item.getSystemId());
            businessService.save(businessContext);
            vo.setBusiness(businessContext);
            context = businessContext;
        } else {
            if (action.equalsIgnoreCase("create")) {
                return ResponseResult.error("businessCode重复！");
            }
            vo.setBusiness(context);
        }
        if (context.getFormId() != null) {
            final ResponseResult<FormTemplateData> result = formClient.findById(context.getFormId());
            if (result == null || result.getCode() == ResultCode.RPC_ERROR.getCode())
                return ResponseResult.error("获取表单信息失败！");
            if (result.getData() != null)
                vo.setFormTemplate(result.getData());
        }
        if (context.getFormInstance() != null && context.getFormInstance() != 0) {
            BusinessData businessData = businessDataService.getById(context.getFormInstance());
            if (businessData != null)
                vo.setFormData(businessData.getContent());
        }
        if (StringUtils.hasLength(context.getFlowInstance())) {
            ResponseResult<TaskVO> responseResult = flowClient.getInstanceTask(context.getFlowInstance());
            if (responseResult == null || responseResult.getCode() == ResultCode.RPC_ERROR.getCode())
                return ResponseResult.error("获取流程信息失败！");
            if (responseResult.getCode() == ResultCode.SUCCESS.getCode()) {
                ExecuteVO executeVO = new ExecuteVO();
                executeVO.setProcessInstanceId(context.getFlowInstance());
                executeVO.setTenantId(String.valueOf(context.getSystemId()));
                if (responseResult.getData() != null) {
                    executeVO.setTaskId(responseResult.getData().getId());
                }
                vo.setExecuteVO(executeVO);
            } else {
                return ResponseResult.error("获取流程信息");
            }
        } else {
            if (context.getFlowId() != null && context.getFlowId() != 0) {
                ResponseResult<FlowData> responseResult = flowClient.getById(context.getFlowId());
                if (responseResult == null || responseResult.getCode() == ResultCode.RPC_ERROR.getCode())
                    return ResponseResult.error("获取流程信息失败！");
                if (responseResult.getData() != null) {
                    ExecuteVO executeVO = new ExecuteVO();
                    executeVO.setProcessKey(responseResult.getData().getProcessKey());
                    executeVO.setTenantId(String.valueOf(context.getSystemId()));
                    vo.setExecuteVO(executeVO);
                } else {
                    return ResponseResult.error("获取流程信息失败");
                }
            }
        }
        return ResponseResult.success(vo);
    }

    /**
     * 此方法要求流程图的第一个用户任务必须为申请人任务
     *
     * @param businessData
     * @return
     */
    @PostMapping("/apply")
    @ApiOperation("事项开启申请")
    public ResponseResult<List<TaskVO>> apply(@RequestBody BusinessData businessData) {
        if (businessData == null || StringUtils.isEmpty(businessData.getBusinessCode())) {
            return ResponseResult.error("参数错误");
        }
        Business business = businessService.getByBusinessCode(businessData.getBusinessCode());
        if (business == null) {
            return ResponseResult.error("未找到对应的businessCode");
        }
        // 配置了表单
        if (business.getFormId() != null && business.getFormId() != 0) {
            if (StringUtils.isEmpty(businessData.getContent())) {
                return ResponseResult.error("表单数据不能为空");
            }
            // 可能是更新表单
            if (business.getFormInstance() != null) {
                businessData.setId(business.getFormInstance());
                businessDataService.lambdaUpdate().eq(BusinessData::getBusinessId, business.getId()).set(BusinessData::getContent, businessData
                        .getContent()).update();
            } else {
                businessData.setBusinessId(business.getId());
                businessData.setTemplateId(business.getFormId());
                businessData.setSystemId(business.getSystemId());
                //申请人，主表叫starter，子表叫approver，同一条申请记录
                businessData.setApprover(businessData.getStarter());
                businessDataService.save(businessData);
                businessService.lambdaUpdate().eq(Business::getId, business.getId()).set(Business::getFormInstance, businessData
                        .getId()).set(Business::getStarter, businessData.getStarter()).update();
            }
        }
        //配置了流程
        if (business.getFlowId() != null && business.getFlowId() != 0) {
            // 存在表单内容，则将表单内容转成map传入流程中
            Map<String, Object> params = (Map<String, Object>) JSON.parse(businessData.getContent());
            if (businessData.getExecuteVO() == null) {
                businessData.setExecuteVO(new ExecuteVO());
                businessData.getExecuteVO().setParams(new HashMap<>(params));
                businessData.getExecuteVO().setStartUser(businessData.getStarter());
                businessData.getExecuteVO().setAssignee(businessData.getStarter());
            } else {
                Map<String, Object> variables = businessData.getExecuteVO().getParams();
                if (variables == null) {
                    variables = new HashMap<>(params);
                } else {
                    variables.putAll(params);
                }
            }
            businessData.getExecuteVO().setNextAssignee("admin");
            // 流程已经启动，此时为执行流程节点
            if (StringUtils.hasLength(business.getFlowInstance())) {
                //调用流程执行方法
                //说明是流程打回重写填写,调用completeTask()接口
                flowClient.publicCompleteTask(businessData.getExecuteVO());
            } else {// 流程未启动，此时为启动流程
                // 调用启动流程方法,并且执行完第一个节点任务
                ResponseResult<String> responseResult = flowClient.startFirstComplete(businessData.getExecuteVO());
                if (responseResult == null || StringUtils.isEmpty(responseResult.getData())) {
                    return ResponseResult.error("事项流程启动失败!");
                }
                // 更新form_data的flow_instance字段
                //获取该流程实例id，更新form_data的flow_instance字段，但是不要更新flow_task字段，让开发者知道这是发起申请的数据(表单数据)记录
                String procInstId = responseResult.getData();
                businessService.lambdaUpdate().eq(Business::getId, business.getId()).set(Business::getFlowInstance, procInstId).update();
                //并且返回后面节点的任务详情
                return ResponseResult.success();
            }
        }

        return ResponseResult.success();
    }

    @PostMapping("/approval")
    @ApiOperation("事项进行审批")
    public ResponseResult approval(@RequestBody BusinessData businessData) {
        if (businessData == null || StringUtils.isEmpty(businessData.getBusinessCode())) {
            return ResponseResult.error("参数错误");
        }
        Business business = businessService.getByBusinessCode(businessData.getBusinessCode());
        if (business == null) {
            return ResponseResult.error("未找到对应的businessCode");
        }
        //配置了流程
        if (business.getFlowId() == null || business.getFlowId() == 0) {
            return ResponseResult.error("未配置流程信息!");
        }

        if (!StringUtils.hasLength(business.getFlowInstance())) {
            return ResponseResult.error("当前事项尚未生成流程实例！");
        }

        // 审批意见需填写
        if (StringUtils.isEmpty(businessData.getContent()) || StringUtils.isEmpty(businessData.getApprover())) {
            return ResponseResult.error("审批信息不能为空");
        }

        // Map<String, Object> params= jsonFormToMap(businessData.getContent());

        Map<String, Object> params = (Map<String, Object>) JSON.parse(businessData.getContent());
        Map<String, Object> variables = businessData.getExecuteVO().getParams();
        if (variables == null) {
            variables = new HashMap<>(params);
            businessData.getExecuteVO().setParams(variables);
        } else {
            variables.putAll(params);
        }
        // 调用流程执行方法
        ResponseResult<String> listResponseResult = flowClient.publicCompleteTask(businessData.getExecuteVO());
        if (listResponseResult != null && listResponseResult.getCode() == 200) {
            //并且将该条记录保存到c_business_data表中
            businessData.setBusinessId(business.getId());
            businessData.setSystemId(business.getSystemId());
            businessData.setFlowInstance(business.getFlowInstance());
            businessData.setFlowTask(businessData.getExecuteVO().getTaskId());
            businessDataService.save(businessData);
            return ResponseResult.success();
        }
        return ResponseResult.error("审批失败");
    }

    @GetMapping("/apply/list")
    @ApiOperation("申请列表")
    public ResponseResult applyList(@ApiParam(value = "审批人") @RequestParam("starter") String starter) {
        LambdaQueryWrapper<Business> qw = new LambdaQueryWrapper<>();
        qw.eq(Business::getStarter, starter);
        qw.orderByDesc(Business::getId);
        List<Business> businessList = businessService.getBaseMapper().selectList(qw);
        return ResponseResult.success(businessList);
    }

    @GetMapping("/tasking/list")
    @ApiOperation("待审批任务")
    public ResponseResult<Page<TaskVO>> taskingList(@ApiParam(value = "审批人") @RequestHeader(value = Constant.BUSINESS_USERNAME, required = false) String username,
                                                    @ApiParam("租户id") @RequestParam("tenantId") String tenantId,
                                                    @ApiParam(value = "变量名") @RequestParam(value = "variableName", required = false) String variableName,
                                                    @ApiParam(value = "变量值") @RequestParam(value = "variableValue", required = false) String variableValue,
                                                    @ApiParam(value = "流程实例id") @RequestParam(value = "processInstanceId", required = false) String processInstanceId,
                                                    @ApiParam(value = "创建时间排序方向:1代表时间升序、-1代表时间降序") @RequestParam("sort") Integer sort,
                                                    @ApiParam(value = "当前页码", example = "1") @RequestParam("current") Integer current,
                                                    @ApiParam(value = "每页大小", example = "10") @RequestParam("pageSize") Integer pageSize) {
        ResponseResult<Page<TaskVO>> responseResult =
                flowClient.findUnDoTaskByAssignee(username, tenantId, variableName, variableValue, processInstanceId, sort,
                        current, pageSize);
        return ResponseResult.success(responseResult.getData());
    }

    @GetMapping("/tasked/list")
    @ApiOperation("已审批列表")
    public ResponseResult taskedList(@ApiParam(value = "审批人") @RequestParam(value = "approver", required = false) String approver,
                                     @ApiParam(value = "系统id") @RequestParam(value = "systemId", required = false) String systemId) {
        LambdaQueryWrapper<BusinessData> qw = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(approver)) {
            qw.eq(BusinessData::getApprover, approver);
        }
        if (!StringUtils.isEmpty(systemId)) {
            qw.eq(BusinessData::getSystemId, systemId);
        }
        qw.orderByDesc(BusinessData::getId);
        List<BusinessData> businessDataList = businessDataService.getBaseMapper().selectList(qw);
        return ResponseResult.success(businessDataList);
    }

    @GetMapping("/page")
    @ApiOperation("分页获取办件列表")
    public ResponseResult<IPage<Business>> page(
            @ApiParam(value = "查询名称") @RequestParam(required = false) String name,
            @ApiParam(value = "当前页码", required = true, example = "1") @RequestParam Integer pageNum,
            @ApiParam(value = "每页大小", required = true, example = "10") @RequestParam Integer pageSize,
            @ApiParam(value = "申请人") @RequestParam(required = false) String starter,
            @ApiParam(value = "系统权限ID") @RequestHeader(Constant.SYSTEM) String systemIds) {
        // ){
        //     String systemIds = "1, 1326390830101028866, 1326391202156765185, 1326391346805727234, 1326391436677079042, 1326391548857933826, 1326391642428661761,"
        //         + "1326391804022611969, 1326391891947806721, 1326398858841829378, 1326807910528876546,1328902971995566081,1330761896646705153,1331786725621538817,1331798987254050817,"
        //         + "1331864533060300802,1341980290758352898,1422488072509575170";
        return ResponseResult.success(businessService.getPage(name, starter, systemIds, pageNum, pageSize));
    }

    @GetMapping("/historyBusinessData/list")
    @ApiOperation("审批历史列表")
    public ResponseResult<List<BusinessDataVo>> historyBusinessData(
            @ApiParam(value = "事项businessCode") @RequestParam String businessCode) {
        Business byBusinessCode = businessService.getByBusinessCode(businessCode);
        if (byBusinessCode == null) {
            return ResponseResult.error("该事项不存在!");
        }
        List<BusinessData> historyBusinessDatas = businessDataService.getHistoryBusinessDataById(byBusinessCode.getId());
        if (CollectionUtils.isEmpty(historyBusinessDatas)) {
            return ResponseResult.error("暂无审批历史!");
        }
        //根据taskId，查历史任务的名称和开始时间、结束时间
        ResponseResult<List<TaskVO>> responseResult =
                flowClient.getHistoryTasksByInstanceId(byBusinessCode.getFlowInstance());
        if (CollectionUtils.isEmpty(responseResult.getData())) {
            return ResponseResult.error("未查到历史审批任务!");
        }
        Map<String, Object> map = new HashMap<>();
        historyBusinessDatas.stream().forEach(e ->
        {
            if (e.getFlowTask() != null) {
                map.put(e.getFlowTask(), e);
            }
        });
        List<BusinessDataVo> list = new ArrayList<>();
        for (TaskVO taskVO : responseResult.getData()) {
            BusinessData businessData = (BusinessData) map.get(taskVO.getId());
            BusinessDataVo businessDataVo = new BusinessDataVo();
            businessDataVo.setFlowTaskName(taskVO.getName());
            businessDataVo.setApprover(taskVO.getAssignee());
            businessDataVo.setTaskCreateTime(taskVO.getCreateTime());
            businessDataVo.setTaskEndTime(taskVO.getEndTime());
            businessDataVo.setItemCode(byBusinessCode.getItemCode());
            businessDataVo.setItemName(byBusinessCode.getItemName());
            if (businessData != null) {
                businessDataVo.setContent(businessData.getContent());
            }
            list.add(businessDataVo);
        }
        return ResponseResult.success(list);
    }

    @DeleteMapping("/business")
    @ApiOperation("删除办件")
    public ResponseResult<String> removeProject(@RequestParam("businessId") Long businessId) {
        return businessService.removeProject(businessId);
    }

    public Map<String, Object> jsonFormToMap(String content) {
        Map<String, Object> params = new HashMap<>();
        if (StringUtils.hasLength(content)) {
            ObjectMapper mapper = new ObjectMapper();
            try {
                JsonNode jsonNode = mapper.readTree(content);
                if (jsonNode != null) {
                    Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();
                    while (fields.hasNext()) {
                        Map.Entry<String, JsonNode> next = fields.next();
                        params.put(next.getKey(), next.getValue());
                    }
                }
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return params;
    }
}
